#![allow(dead_code)]

use anyhow::{Ok, Result};
use reqwest::header::HeaderMap;

/// 获取实时行情数据
/// <br/>stock_codes 股票代码，多个用,隔开
pub async fn get_market_list(stock_codes: &str) -> Result<Vec<MarketItem>> {
    let url: String = format!("https://hq.sinajs.cn/list={}", stock_codes);

    let mut headers = HeaderMap::new();
    headers.insert("Referer", "https://finance.sina.com.cn/".parse().unwrap());

    let client = reqwest::Client::new();
    let body = client
        .get(url)
        .headers(headers)
        .send()
        .await
        .unwrap()
        .text()
        .await
        .unwrap();

    let res = into_entities(body).unwrap();
    return Ok(res);
}

fn into_entities(text: String) -> Result<Vec<MarketItem>> {
    let mut list = Vec::<MarketItem>::new();
    for item in text.split("\n") {
        let reg_code = regex::Regex::new(r"var hq_str_(?<code>.*)=").unwrap();
        let Some(code) = reg_code.captures(item) else { continue; };
        let stock_code = code["code"].to_string();

        let reg = regex::Regex::new("([\",'])(?<market>.*)([\",'])").unwrap();
        let Some(res) = reg.captures(item) else { continue; };

        let mut entity = into_entity(res["market"].to_string())?;
        entity.stock_code = stock_code;

        list.push(entity);
    }
    return Ok(list);
}

fn into_entity(text: String) -> Result<MarketItem> {
    let arr = text.split(",").collect::<Vec<&str>>();
    let market = MarketItem {
        stock_code: String::from(""),
        stock_name: arr[0].replace("\"", "").to_owned(),
        today_start_price: arr[1].parse::<f64>().unwrap(),
        lastday_end_price: arr[2].parse::<f64>().unwrap(),
        now_price: arr[3].parse::<f64>().unwrap(),
        today_max_price: arr[4].parse::<f64>().unwrap(),
        today_min_price: arr[5].parse::<f64>().unwrap(),
        buy_bidding_price: arr[6].parse::<f64>().unwrap(),
        sell_bidding_price: arr[7].parse::<f64>().unwrap(),
        trading_number: arr[8].parse::<i32>().unwrap(),
        trading_volume: arr[9].parse::<f64>().unwrap(),
        buy_level: vec![
            MarketLevel::from(arr[11], arr[10]),
            MarketLevel::from(arr[13], arr[12]),
            MarketLevel::from(arr[15], arr[14]),
            MarketLevel::from(arr[17], arr[16]),
            MarketLevel::from(arr[19], arr[18]),
        ],
        sell_level: vec![
            MarketLevel::from(arr[21], arr[20]),
            MarketLevel::from(arr[23], arr[22]),
            MarketLevel::from(arr[25], arr[24]),
            MarketLevel::from(arr[27], arr[26]),
            MarketLevel::from(arr[29], arr[28]),
        ],
        date_time: format!("{} {}", arr[30], arr[31]),
    };

    return Ok(market);
}

#[derive(serde::Deserialize, serde::Serialize, Debug, Default)]
pub struct MarketItem {
    ///股票代码
    pub stock_code: String,
    ///股票名称
    pub stock_name: String,
    ///今日开盘价
    pub today_start_price: f64,
    ///昨日收盘价
    lastday_end_price: f64,
    ///当前价格
    pub now_price: f64,
    ///今日最高价
    pub today_max_price: f64,
    ///今日最低价
    pub today_min_price: f64,
    ///竞买价
    pub buy_bidding_price: f64,
    ///竞卖价
    pub sell_bidding_price: f64,
    ///成交的股票数(股）
    pub trading_number: i32,
    ///成交金额(元)
    pub trading_volume: f64,
    ///五档买
    pub buy_level: Vec<MarketLevel>,
    ///五档卖
    pub sell_level: Vec<MarketLevel>,
    ///时间
    pub date_time: String,
}

#[derive(serde::Deserialize, serde::Serialize, Debug, Default)]
pub struct MarketLevel {
    ///价位
    price: f32,
    ///股数
    number: i32,
}

impl MarketLevel {
    pub fn from(price_str: &str, number_str: &str) -> Self {
        return MarketLevel {
            price: price_str.parse::<f32>().unwrap(),
            number: number_str.parse::<i32>().unwrap(),
        };
    }
}

#[cfg(test)]
mod market_test {
    use super::*;
    use core::result::Result::Ok;
    use tokio::test;

    #[test]
    async fn test_get_market_list() {
        match get_market_list("sh600900,sz002320").await {
            Ok(res) => println!("{:?}", res),
            Err(err) => println!("{:?}", err),
        }
    }
}
